<?php
namespace PI;
require_once(__DIR__."/core.inc.php");
require_once(__DIR__."/db.inc.php");

class User{
    public $Id;
    public $Username;
    public $Nickname;
    public $Code;
    public $Roles;
    public $Permissions;
}

class Permission{
    public $allows;
    public $denies;

    public function check(string $name):bool{
        if($this->denies && in_array($name,$this->denies)) return false;
        if($this->allows && !in_array($name,$this->allows)) return false;
        return true;
    }
}

class WhereBuilder{
    public $conditions;
    public $view_model;
    public $permssion;
    public $param_values;
    public $make_field;
    function __construct(ViewModel $vm){
        $this->view_model = $vm;
        //$this->permssion = $perm;
        $this->conditions = [];
        $this->param_values=[];
    }
    function eq($name):WhereBuilder{
        
        $value = $this->view_model->$name;
        if($value){
            $this->conditions[] = $this->make_field($name)."=?";
            $this->param_values[] = $value;
        }
        
        return $this;
    }
    function teq($name):WhereBuilder{
        
        if($this->permssion && !$this->permssion->check($name)) return $this;
        $value = $this->view_model->$name;
        if($value){
            $this->conditions[] = $this->make_field($name)."=?";
            $this->param_values[] = trim($this->view_model->$name);
        }
       
        return $this;
    }

    function contains($name):WhereBuilder{
        if($this->permssion && !$this->permssion->check($name)) return $this;
        $value = str_replace("'","''",trim($this->view_model->$name));
        if($value)$this->conditions[] = $this->make_field($name)." LIKE ('$value')";
        return $this;
    }
    function range($name):WhereBuilder{
        if($this->permssion && !$this->permssion->check($name)) return $this;
        $fname = $this->make_field($name);
        $where = "";
        $min_field = $name."_min";
        $min_value = trim($this->view_model->$min_field);
        if($min_value!==""){
            $where.="$fname>=?";
            $this->param_values[] = $min_value;
        }
        $max_field = $name."_max";
        $max_value = trim($this->view_model->$max_field);
        if($min_value!==""){
            if($where) $where .= " AND ";
            $where.="$fname>=?";
            $this->param_values[] = $max_value;
        }

        if($where)$this->conditions[] = $where;
        
        return $this;
    }

    function to_sql(){
        return implode(" AND ",$this->conditions);
    }

    function make_field(string $name):string{return $name;}
}

class ListViewModel extends \PI\ViewModel{
    public $page_index;
    public $page_size;
    public $page_count;
    public $total_count;
    public $list_items;
    public $order_asc;
    public $order_desc;

    public function set_total(int $total):ListViewModel{
        $this->total_count = $total;
        if(!$this->page_size || $this->page_size<1) $this->page_size=10;
        $this->page_count = \intval($total/$this->page_size);
        if(($total%$this->page_size)>0) $this->page_count++;
        if($this->page_index>$this->PageCount) $this->page_index = $this->PageCount;
        if(!$this->page_index || $this->page_index<1) $this->page_index=1;
       
        return $this;
    }

    public function fill(Dbset $dbset, $where,array $allows=null,array $denies=null):ListViewModel{
        if($where) {
            if(is_string($where)) $dbset->where($where);
            else {
                if($where instanceof WhereBuilder){
                    $dbset->where($where->to_sql())->set_parameters($where->param_values); 
                }
            }
        }
        $this->set_total($dbset->query_count());
        $dbset->allowed_fields($allows)->denied_fields($denies)->take($this->page_size)->skip(($this->page_index-1)* $this->page_size);

        $this->list_items = $dbset->to_array();        
        return $this;
    }

}


class ModelController extends Controller{
    public $dbset;
    static $__viewModelClassname;
    static $__listViewModelClassname;
    static $__dbTablename;
    function __construct(\PI\Database $db)
    {
        if(isset($this::$__dbTablename)) $this->dbset = $db->dbset($this::$__dbTablename);
        else {
            $tbname = get_class($this);
            $at = strrpos($tbname,"\\");
            
            if($at!==false){
                $tbname = substr($tbname,$at+1);
            }
            $at = strpos($tbname,"Controller");
            if( $at===(strlen($tbname)-10)) $tbname = substr($tbname,0,strlen($tbname)-10);
            $this->dbset = $db->dbset($tbname);
        }
    }

    function index(ListViewModel $vm){
        return $this->list($vm);
    }
    

    function list(ListViewModel $vm){
        $perm = $this->check_permission($this->user,"list",$vm);
        if(!$perm) return $this->error("permission","没有访问权限",$vm);
        $vm->fill($this->dbset,$this->make_listWhere($this->dbset,$vm,$perm));
        return $vm;

    }
    

    function new(ViewModel $vm){
        $perm = $this->check_permission($this->user,"new",$vm);
        if(!$perm) return $this->error("permission","没有访问权限",$vm);

        if(!$vm || !$vm->Id){
            return $vm;
        }else {
            if(!$vm->validate($perm->allows,$perm->denies)) return $vm;
            $this->dbset->add($vm);
            return $vm;
        }
    }

    function detail($id){
        $perm = $this->check_permission($this->user,"detail",null,$id);
        if(!$perm) return $this->error("permission","没有访问权限",null);
        $vmt = static::$__viewModelClassname;
        if($vmt)$vm = new $vmt();
        else $vm = new ViewModel();
        $this->dbset->load($id)->to_object($vm);
        return $vm;
    }
    function modify(ViewModel $vm,$id){
        $perm = $this->check_permission($this->user,"modify",$vm,$id);
        if(!$perm) return $this->error("permission","没有访问权限",$vm);

        if(!$vm){
            $this->dbset->load($id)->to_object($vm);
            return $vm;
        }else {
            $vm->set_id($id);
            $this->dbset->save($vm);
            return $vm;
        }
    }

    function delete($id){
        $perm = $this->check_permission($this->user,"delete",null,$id);
        if(!$perm) return $this->error("permission","没有访问权限",$id);
    }

    protected function check_permission(User $user=null,string $action,$data,$id=null){
        return new Permission();
    }
    protected function make_listWhere(\PI\DbSet $dbset,ListViewModel $vm,\PI\Permission $perm=null):WhereBuilder{
        $builder = new WhereBuilder($vm,$perm,null);
        $builder->contains("Username")->contains("Code");
        return $builder;
    }
}

